package net.sureon.web.admin;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sureon.app.AppContext;
import net.sureon.biz.CompanyBO;
import net.sureon.biz.CompanyMgr;
import net.sureon.biz.GroupBO;
import net.sureon.biz.GroupMgr;
import net.sureon.biz.TitaonMailHelper;
import net.sureon.biz.UserBO;
import net.sureon.biz.UserMgr;
import net.sureon.common.SureonConstants;
import net.sureon.common.exception.SureonException;
import net.sureon.common.security.Role;
import net.sureon.common.security.SecurityUtils;
import net.sureon.dao.User;

import org.apache.commons.lang.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.mvc.SimpleFormController;

@SuppressWarnings("unchecked")
public class ManageUser extends SimpleFormController implements Controller {
	private UserMgr userMgr;
	private GroupMgr groupMgr;
	private CompanyMgr companyMgr;

	/**
	 * @return the userMgr
	 */
	public UserMgr getUserMgr() {
		return userMgr;
	}

	/**
	 * @param userMgr
	 *            the userMgr to set
	 */
	public void setUserMgr(UserMgr userMgr) {
		this.userMgr = userMgr;
	}

	/**
	 * @return the groupMgr
	 */
	public GroupMgr getGroupMgr() {
		return groupMgr;
	}

	/**
	 * @param groupMgr
	 *            the groupMgr to set
	 */
	public void setGroupMgr(GroupMgr groupMgr) {
		this.groupMgr = groupMgr;
	}

	/**
	 * @return the companyMgr
	 */
	public CompanyMgr getCompanyMgr() {
		return companyMgr;
	}

	/**
	 * @param companyMgr
	 *            the companyMgr to set
	 */
	public void setCompanyMgr(CompanyMgr companyMgr) {
		this.companyMgr = companyMgr;
	}

	private static final String ATTRI_USERS = "users";
	private static final String ACTION = "action";
	private static final String ID = "id";
	private static final String ATTRI_USERFORM = "userForm";

	protected Map referenceData(HttpServletRequest request, Object command,
			Errors errors) throws Exception {
		Map result = new HashMap();
		String action = request.getParameter(ACTION);
		String id = request.getParameter(ID);
		if (action != null && id != null) {
			processStandaloneAction(command, action, id);
		}
		result.put(ATTRI_USERS, generateUserListResult());
		UserForm form = (UserForm) command;
		form.setGroupList(buildGroupDropdownDisplay(AppContext.getCompanyID()));
		form.setRoleList(Role.getPredefinedRoles());
		result.put(ATTRI_USERFORM, command);
		return result;
	}

	private void processStandaloneAction(Object command, String action,
			String id) throws SureonException {
		long userID = Long.parseLong(id);
		UserBO user = userMgr.getUser(AppContext.getCompanyID(), userID);
		if ("freeze".equals(action)) {
			if (user.getUserID() > 1 && user.isActive()) {/*
														 * userid=1 is not
														 * allowed to
														 * deactivated.
														 */
				user.deactivateUser();
				userMgr.updateUser(user);
				sendUserReminderMail(
						TitaonMailHelper.MAIL_NAME_ACCOUNT_DEACTIVATED, user
								.getUserID(), null);
			}
		} else if ("edit".equals(action)) {
			UserForm form = (UserForm) command;
			form.setUserID(user.getUserVO().getUserID());
			form.setTitle(user.getUserVO().getTitle());
			form.setOfficeTel(user.getUserVO().getOfficeTel());
			form.setFax(user.getUserVO().getFax());
			form.setGroupID(user.getUserVO().getGroupID());
			form.setRealName(user.getUserVO().getRealName());
			form.setMobileTel(user.getUserVO().getMobileTel());
			form.setEmail(user.getUserVO().getEmail());
			form.setRole(user.getUserVO().getRole());
		} else if ("active".equals(action)) {
			if (!user.isActive()) {
				user.activateUser();
				userMgr.updateUser(user);
				sendUserReminderMail(
						TitaonMailHelper.MAIL_NAME_ACCOUT_ACTIVATED, user
								.getUserID(), null);
			}
		}
	}

	private void sendUserReminderMail(String mailName, long userID,
			String initPassword) throws SureonException {
		CompanyBO company = companyMgr.getCompany(AppContext.getCompanyID());
		UserBO user = userMgr.getUser(AppContext.getCompanyID(), userID);
		TitaonMailHelper.getInstance().sendUserReminderMail(mailName, company,
				user, initPassword);
	}

	private List<UserBO> generateUserListResult() throws Exception {
		// UserSession sess = AppContext.getCurrentUserSession();
		List<UserBO> list = userMgr.getUserByCompanyID(AppContext
				.getCompanyID(), 0, 1000);
		return list;
	}

	protected ModelAndView onSubmit(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {
		UserForm userForm = (UserForm) command;
		if (userForm.getUserID() > 0) {
			if (userForm.getUserID() > 1) {
				UserBO userBO = userMgr.getUser(AppContext.getCompanyID(),
						userForm.getUserID());
				updateUser(userBO, userForm);
			} else {
				logger
						.error("failed to edit userid=1 user, it is not allowed, current user:"
								+ AppContext.getUserID());
			}
		} else {
			createUser(userForm);
		}
		userForm.reset();
		ModelAndView view = new ModelAndView(this.getSuccessView());
		Map result = new HashMap();
		result.put(ATTRI_USERS, generateUserListResult());
		userForm.setRoleList(Role.getPredefinedRoles());
		userForm.setGroupList(buildGroupDropdownDisplay(AppContext
				.getCompanyID()));

		result.put(ATTRI_USERFORM, userForm);
		view.addAllObjects(result);

		// response.sendRedirect("manageUser.do");
		return view;
	}

	private void updateUser(UserBO userBO, UserForm userForm)
			throws SureonException {
		User vo = userBO.getUserVO();
		vo.setEmail(userForm.getEmail());
		vo.setFax(userForm.getFax());
		vo.setMobileTel(userForm.getMobileTel());
		vo.setOfficeTel(userForm.getOfficeTel());
		vo.setRealName(userForm.getRealName());
		vo.setRole(userForm.getRole());
		if (StringUtils.isNotBlank(userForm.getPassword())) {
			vo.setPassword(SecurityUtils.generateSHA512Hash(vo.getSalt() + ":"
					+ userForm.getPassword()));
		}
		vo.setStatus(SureonConstants.USER_STATUS_ACTIVE);
		vo.setTitle(userForm.getTitle());
		vo.setUserName(userForm.getUserName());

		if (userBO.getUserVO().getGroupID() != userForm.getGroupID()) {
			// handle old group
			GroupBO old = groupMgr.getGroup(AppContext.getCompanyID(), userBO
					.getUserVO().getGroupID());
			if (old.getGroupVO().getGroupManager() == userBO.getUserID()) {
				/*
				 * if i am the group manager
				 */
				logger
						.error("you'd better find a another manager for the gorup before reassign this to another group., old groupID"
								+ old.getGroupID()
								+ ",new groupID="
								+ userBO.getUserVO().getGroupID());
				throw new SureonException("can_not_reassign_group_manager_out");
			}
		}

		vo.setGroupID(userForm.getGroupID());

		userMgr.updateUser(userBO);

		// 如果更新为groupManager，则同时更新组信息
		if (Role.ROLE_NAME_GROUPADMIN.equals(userForm.getRole())) {
			GroupBO group = groupMgr.getGroup(vo.getCompanyID(), vo
					.getGroupID());
			if (group.getGroupVO().getGroupManager() == 0) {
				group.getGroupVO().setGroupManager(vo.getUserID());
				groupMgr.updateGroup(group);
			}
		}
	}

	private void createUser(UserForm userForm) throws SureonException {
		User vo = new User();
		vo.setCompanyID(AppContext.getCompanyID());
		vo.setEmail(userForm.getEmail());
		vo.setFax(userForm.getFax());
		vo.setGroupID(userForm.getGroupID());
		vo.setMobileTel(userForm.getMobileTel());
		vo.setOfficeTel(userForm.getOfficeTel());
		vo.setRealName(userForm.getRealName());
		vo.setRole(userForm.getRole());
		vo.setSalt(SecurityUtils.generateRandomString(10, 20));
		vo.setPassword(SecurityUtils.generateSHA512Hash(vo.getSalt() + ":"
				+ userForm.getPassword()));
		vo.setStatus(SureonConstants.USER_STATUS_ACTIVE);
		vo.setTitle(userForm.getTitle());
		vo.setRegisterDate(new Date());
		vo.setUserName(userForm.getEmail());

		UserBO userBo = new UserBO(vo);
		long userID = userMgr.insertUser(userBo);

		if (Role.ROLE_NAME_GROUPADMIN.equals(userForm.getRole())) {
			GroupBO group = groupMgr.getGroup(vo.getCompanyID(), vo
					.getGroupID());
			if (group.getGroupVO().getGroupManager() == 0) {
				group.getGroupVO().setGroupManager(userID);
				groupMgr.updateGroup(group);
			}
		}
		sendUserReminderMail(TitaonMailHelper.MAIL_NAME_ACCOUNT_CREATED, vo
				.getUserID(), userForm.getPassword());
	}

	private List buildGroupDropdownDisplay(long companyID)
			throws SureonException {
		List<GroupDropDownDisplay> list = new ArrayList<GroupDropDownDisplay>();
		GroupBO topGroup = groupMgr.getCompanyTopGroup(companyID);
		recusiveGenerateGroupList(topGroup, list, 0);
		return list;
	}

	private void recusiveGenerateGroupList(GroupBO group,
			List<GroupDropDownDisplay> addTo, int level) {
		addTo.add(new GroupDropDownDisplay(group.getGroupID(), strPrefix(level,
				group.getGroupVO().getGroupName())));
		for (GroupBO subGroup : group.getChildGroups()) {
			recusiveGenerateGroupList(subGroup, addTo, level + 1);
		}
	}

	private static final String prefix = "---";
	private static final String initial = "|-";

	private String strPrefix(int level, String groupName) {
		StringBuffer buff = new StringBuffer(initial);
		for (int i = 0; i < level; i++) {
			buff.append(prefix);
		}
		buff.append(groupName);
		return buff.toString();
	}

	private static class GroupDropDownDisplay {
		private long groupID;
		private String groupName;

		private GroupDropDownDisplay(long groupID, String groupName) {
			this.groupID = groupID;
			this.groupName = groupName;
		}

		/**
		 * @return the groupID
		 */
		public long getGroupID() {
			return groupID;
		}

		/**
		 * @return the groupName
		 */
		public String getGroupName() {
			return groupName;
		}

	}
}
